package cn.topcodes.tcsf.admin.service.impl;

import cn.topcode.unicorn.utils.FileUtil;
import cn.topcode.unicorn.utils.IOUtil;
import cn.topcode.unicorn.utils.UuidUtil;
import cn.topcodes.tcsf.admin.commons.generic.GenericService;
import cn.topcodes.tcsf.admin.domain.entity.SysFile;
import cn.topcodes.tcsf.admin.service.ApplicationConfig;
import cn.topcodes.tcsf.admin.service.SysFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
import java.io.*;

@Service
@Transactional(readOnly=true)
public class SysFileServiceImpl extends GenericService<SysFile> implements SysFileService {

	@Autowired
	private ApplicationConfig config;

	/*实际存储位置*/
	private String storageFolder;

	/*临时文件存储位置*/
	private String tempFolder;

	@PostConstruct
	public void init() {
		storageFolder = config.getFileFolder() + "storage" + File.separator;
		tempFolder = config.getFileFolder() + "temp" + File.separator;
	}

	/**
	 * 文件分片组装处理
	 * @param chunks    总片数
	 * @param chunk     当前片数
	 * @param in        分片数据输入流
	 */
	@Override
	public Long saveFile(String uuid, int chunks, int chunk, InputStream in,
					   String filename, long size, String mime, String md5) throws IOException {
		/*临时文件块名*/
		String tempFilename = uuid + "_" + chunk;
		/*临时文件路径*/
		String tempFilePath = tempFolder + File.separator + tempFilename;
		File tempFile = new File(tempFilePath);
		if (!tempFile.exists() || !tempFile.isFile()) {
			FileUtil.copyToFile(in, tempFile);
			//  判断分片是否传输完成
			boolean isComplete = true;
			for (int i = 1; i <= chunks; i++) {
				String chunkFilename = uuid + "_" + i;
				File chunkFile = new File(chunkFilename);
				if (!chunkFile.exists()) {
					isComplete = false;
				}
			}
			//  分片传输完成后立即开始组装分片
			if (isComplete) {
				String targetFilePath = storageFolder + uuid;
				File targetFile = new File(targetFilePath);
				//	文件已存在
				/*if(targetFile.exists()) {
					return null;
				}*/
				FileOutputStream out = new FileOutputStream(targetFile);
				for (int i = 1; i <= chunks; i++) {
					String chunkFilename = uuid + "_" + i;
					File chunkFile = new File(chunkFilename);
					FileInputStream chunkFileIn = new FileInputStream(chunkFile);
					IOUtil.copyTo(chunkFileIn, out);
					chunkFileIn.close();
				}
				out.close();
				return this.saveFile(filename,md5,mime,uuid,targetFile.length());
			}
		}
		return null;
	}

	@Transactional(readOnly = false,propagation = Propagation.REQUIRES_NEW)
	private Long saveFile(String filename,String md5,String mime,String path, long size) {
		SysFile fileInfo = new SysFile();
		fileInfo.setFileName(filename);
		fileInfo.setMd5(md5);
		fileInfo.setMime(mime);
		fileInfo.setPath(path);
		fileInfo.setSize(size);
		fileInfo.setRefCount(0);
		return super.create(fileInfo);
	}

	@Override
	public InputStream readFile(Long fileId) throws FileNotFoundException {
		SysFile sysFile = this.findOne(fileId);
		Assert.notNull(sysFile);
		String filePath = storageFolder + sysFile.getPath();
		File file = new File(filePath);
		if(!file.exists() || !file.isFile()) {
			throw new FileNotFoundException();
		}
		return new FileInputStream(file);
	}

    @Override
	@Transactional(readOnly = false)
    public Long saveFile(InputStream in, long size, String originalFilename, String contentType) throws IOException {
		String uuid = this.getTargetStorageFile();
		File targetFile = new File(storageFolder + uuid);
		File parentFolder = targetFile.getParentFile();
		if(!parentFolder.exists() || !parentFolder.isDirectory()) {
			if(!parentFolder.mkdirs()) {
				throw new IllegalStateException(parentFolder + "文件夹创建失败");
			}
		}
		FileUtil.copyToFile(in, targetFile);
		SysFile fileInfo = new SysFile();
		fileInfo.setSize(size);
		fileInfo.setFileName(originalFilename);
		fileInfo.setPath(uuid);
		fileInfo.setRefCount(0);
		fileInfo.setMime(contentType);
		return this.create(fileInfo);
    }

    private String getTargetStorageFile() {
		String uuid = UuidUtil.getUUID();
		File targetFile = null;
		for(targetFile = new File(storageFolder + UuidUtil.getUUID());
			targetFile.exists() && targetFile.isFile() ;
			targetFile = new File(storageFolder + UuidUtil.getUUID()));
		return uuid;
	}

	@Override
	@Transactional(readOnly = false)
	public SysFile delete(Long id) {
		SysFile sysFile = this.findOne(id);
		Assert.notNull(sysFile);
		if(sysFile.getRefCount() <= 1) {
			File file = new File(storageFolder + sysFile.getPath());
			if(file.exists() && file.isFile()) {
				file.delete();
			}
			super.delete(id);
		}else {
			sysFile.setRefCount(sysFile.getRefCount() - 1);
			this.update(sysFile);
		}
		return sysFile;
	}

	@Override
	public String getStorageFolder() {
		return storageFolder;
	}

	@Override
	public String getTempFolder() {
		return tempFolder;
	}

	@Override
	public String generateStoragePath(String dir) {
		return this.getStorageFolder() + dir + File.separator + UuidUtil.getUUID();
	}
}
